
function getprojectbasepath()
    local path_base
    do
        local project_path = exec.args[1]
        if not project_path then
            project_path = requestproject()
            if not project_path then
                return nil
            end
        end
        
        local path,file = project_path:match("^(.-)[\\/]?([^\\/]+)$")
        
        if (#path > 0) then
            lfs.chdir(path)
        end
        
        path_base = file:lower():match("()%.project%.lua$")
        
        if not path_base then
            error("Invalid project file - must end .project.lua",2)
        end
        
        return file:sub(1, path_base-1)
    end
end

local dots = {['.'] = true, ['..'] = true}

function runbuildscript(script)
    local build_scope = {
        resources = {}
    }
    
    local project_cabinet = {}
    
    local cabinets_root = {
        PROJECT = project_cabinet
    }
    
    local function globmatcher(glob)
        local is_glob
        
        glob = glob:lower()
        
        local pattern = "^" .. glob:gsub("[%*%?%[%]%.%^%$%(%)%-]",
            function(m)
                if (m == '*') then
                    is_glob = true
                    return '.*'
                elseif (m == '?') then
                    is_glob = true
                    return '.'
                end
                return '%' .. m
            end
        ) .. "$"
        
        if not is_glob then
            return function(txt)  return (txt:lower() == glob);  end
        end
        
        if pattern == '^.*$' then
            return function()  return true;  end
        end
        if pattern:sub(1,3) == '^.*' then
            pattern = pattern:sub(4)
        end
        if pattern:sub(-3) == '.*$' then
            pattern = pattern:sub(1,-4)
        end
        return function(txt)  return txt:lower():match(pattern);  end
    end
    
    local function resources_basefunc(pattern, recurse, callback)
    
        local path,file = pattern:match('^(.-)[/\\]?([^//\]*)$')
        
        if (path == nil) or (#path == 0) then
            path = '.'
        end
        
        if path:match("[%*%?]") then
            error('Only the file part of the patch can contain wildcard characters, not the path', 3)
        end
        
        local revdir = lfs.currentdir()
        lfs.chdir(path)
        local fullpath = lfs.currentdir()
        lfs.chdir(revdir)
        
        if not ((fullpath:sub(1,#revdir) == revdir) and (#fullpath==#revdir or fullpath:match("^[\\/]", #revdir+1))) then
            error("Resource files cannot be outside the project's base directory\n(" .. revdir .. ")",3)
        end
        
        path = fullpath:sub(#revdir+2)
        if (#path == 0) then
            path = '.'
        end
        
        if not (recurse or file:match("[%*%?]")) then
            return callback(path, file)
        end
        
        local matcher = globmatcher(file)
    
        local processdir
        if recurse then
        
            function processdir(dir)
                for child in lfs.dir('.') do
                    local mode = lfs.attributes(child,'mode')
                    if (mode == 'directory') and (child ~= '.') and (child ~= '..') then
                        local revdir = lfs.currentdir()
                        lfs.chdir(child)
                        processdir(dir .. '\\' .. child)
                        lfs.chdir(revdir)
                    elseif (mode == 'file') and matcher(child) then
                        callback(dir, child)
                    end
                end
            end
        
        else
        
            function processdir(dir)
                for child in lfs.dir('.') do
                    local mode = lfs.attributes(child,'mode')
                    if (mode == 'file') and matcher(child) then
                        callback(dir, child)
                    end
                end
            end
        
        end
    
        local revdir = lfs.currentdir()
        processdir(path)
        lfs.chdir(revdir)

    end
    
    function build_scope.resources.add(pattern, recurse)
        return resources_basefunc(pattern, recurse,
            function(path, file)
                local current = project_cabinet
                for step in path:gmatch("[^\\/]+") do
                    if (step ~= '.') then
                        local new_current = current[step]
                        if not new_current then
                            new_current = {}
                            current[step] = new_current
                        end
                        current = new_current
                    end
                end
                current[file] = path .. '\\' .. file
            end
        )
    end
    
    function build_scope.resources.remove(pattern, recurse)
        return resources_basefunc(pattern, recurse,
            function(path, file)
                local current = project_cabinet
                for step in path:gmatch("[^\\/]+") do
                    if (step ~= '.') then
                        local new_current = current[step]
                        if not new_current then
                            new_current = {}
                            current[step] = new_current
                        end
                        current = new_current
                    end
                end
                current[file] = nil
            end
        )
    end
    
    setfenv(script, build_scope)
    
    script()
    
    local buf = {'return '}
    
    local push_table do
        function push_table(t)
            buf[#buf+1] = '{'
            for k,v in pairs(t) do
                buf[#buf+1] = ('[%q]='):format(k)
                if type(v) == 'table' then
                    push_table(v)
                elseif type(v) == 'string' then
                    buf[#buf+1] = ('%q'):format(v)
                else
                    buf[#buf+1] = tostring(v)
                end
                buf[#buf+1] = ';'
            end
            buf[#buf+1] = '}'
        end
    end
    
    return cabinets_root
end
